from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkRenderer,
    vtkRenderWindow,
    vtkCellPicker,
    vtkPointPicker,
    vtkHardwareSelector,
    vtkPolyDataMapper,
)

from vtkmodules.vtkInteractionStyle import (
    vtkInteractorStyleTrackballCamera, 
    vtkInteractorStyleMultiTouchCamera,
    vtkInteractorStyleFlight,
    vtkInteractorStyleTerrain
)

from vtkmodules.vtkCommonMath import vtkMatrix4x4


from vtkmodules.vtkCommonCore import (
    vtkFloatArray, 
    vtkInformation,
    vtkInformationObjectBaseKey
)

from vtkmodules.vtkCommonDataModel import (
    vtkSelectionNode
)


import math
import datetime

from .Renderer import *

# pick scene-node
class SceneNodePicker(vtkHardwareSelector):
    def __init__(self) -> None:
        pass
        #self.selector = vtkHardwareSelector()
        #self.SetFieldAssociation(vtkDataObject.FIELD_ASSOCIATION_CELLS)

    def Pick(self, x, y):
        self.SetArea(x, y, x, y)
        res = self.Select()
        if res.GetNumberOfNodes() > 0:
            # only get the first one...
            node = res.GetNode(0)
            prop = node.GetProperties()
            id = node.GetSelectionList().GetValue(0) 

            key = vtkSelectionNode.PROP()
            if prop.Has(key):
                actor = key.Get(prop)
                # check if it is an instance actor...
                if hasattr(actor, 'scene'):
                    return actor, id
        return None, None
               
        
class GLTFInteractorStyle(vtkInteractorStyleMultiTouchCamera):
#class GLTFInteractorStyle(vtkInteractorStyleTerrain):
    def __init__(self):
        super(GLTFInteractorStyle, self).__init__()
        
        self.AddObserver("LeftButtonPressEvent", self.OnLeftButtonDown)
        self.AddObserver("RightButtonPressEvent", self.OnRightButtonDown)
        self.AddObserver("MiddleButtonPressEvent", self.OnMiddleButtonDown)
        
        # for double click...
        self.NumberOfClicks = 0
        self.LastMouseX = 0
        self.LastMouseY = 0
        self.LastMouseBtn = -1
        self.LastTimestamp = datetime.datetime.now()
        
        self.DoubleClickDistance = 5
        self.DoubleClickInterval = 0.3  #seconds
   
        self.picker = SceneNodePicker()
        self.lastPick = None

        # renderers
        self.outline = None

    def SetDefaultRenderer(self, renderer):
        self.picker.SetRenderer(renderer)
        super().SetDefaultRenderer(renderer)

    def SetOutlineRenderer(self, renderer):
        self.outline = renderer

    def _processMouseClick(self, x, y, btn):
        self.NumberOfClicks += 1

        # get distance snce last click
        xdist = self.LastMouseX - x
        ydist = self.LastMouseY - y
        moveDistance = math.sqrt(xdist * xdist + ydist * ydist)

        # get time elapsed
        now = datetime.datetime.now()
        elapsed = (now - self.LastTimestamp).total_seconds()

        if self.LastMouseBtn != btn or \
                elapsed > self.DoubleClickInterval or \
                moveDistance > self.DoubleClickDistance:            
            self.NumberOfClicks = 1

        self.LastMouseX = x
        self.LastMouseY = y
        self.LastMouseBtn = btn
        self.LastTimestamp = now

    def OnLeftButtonDown(self, obj, event):
        iren = self.GetInteractor()
        win  = iren.GetRenderWindow()
        x, y = iren.GetEventPosition()    
        self._processMouseClick(x, y, 1)            
        
        # pick node with left button double click
        if self.NumberOfClicks == 2:
            self.NumberOfClicks = 0
            actor, id = self.picker.Pick(x, y)
            if actor == None or id == None:            
                self.outline.Clear()
                self.lastPick = None
            else:    
                scene = actor.scene
                node  = actor.GetNode(id) 
                self.outline.Clear()
                self.outline.AddSceneNode(scene, node)
                self.lastPick = [scene, node]
                print("Pick: ({}, {}) - Scene({}) - Node({})".format(x, y, scene.name, node.name)) 
               
            # need to update render
            win.Render()
        else:
            super().OnLeftButtonDown()


    def OnRightButtonDown(self, obj, event):        
        iren = self.GetInteractor()
        win  = iren.GetRenderWindow()
        x, y = iren.GetEventPosition()        
        self._processMouseClick(x, y, 2)   

        if self.NumberOfClicks == 2:
            self.NumberOfClicks = 0    

            pixel = vtkFloatArray()
            win.GetRGBAPixelData(x, y, x, y, 0, pixel, 0)
            print("pixel=({}, {}), value=({:.2f}, {:.2f}, {:.2f}, {:.2f})"
                .format(x, y,
                    pixel.GetValue(0),
                    pixel.GetValue(1),
                    pixel.GetValue(2),
                    pixel.GetValue(3)))
        else:
            super().OnRightButtonDown()


    def OnMiddleButtonDown(self, obj, event):        
        iren = self.GetInteractor()
        win  = iren.GetRenderWindow()
        x, y = iren.GetEventPosition()
        self._processMouseClick(x, y, 3)   

        if self.NumberOfClicks == 2:
            self.NumberOfClicks = 0 

            t0 = datetime.datetime.now()
            actor, id = self.picker.Pick(x, y)
            t1 = datetime.datetime.now()
            print((t1-t0).total_seconds())
            win.Render()

        else:  
            super().OnMiddleButtonDown()
